//|||||||||||||||||||||||||||||||||||||||||||||||

#include "Game1State.hpp"
#include "Game1FinishedState.hpp"
#include "GameEntity.hpp"

#include <math.h>
#include <OgreAxisAlignedBox.h>

//|||||||||||||||||||||||||||||||||||||||||||||||

using namespace Ogre;

//|||||||||||||||||||||||||||||||||||||||||||||||



//|||||||||||||||||||||||||||||||||||||||||||||||

Game1State::Game1State()
{
    m_bQuit             = false;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::enter()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Entering GameState...");

    m_pSceneMgr = OgreFramework::getSingletonPtr()->m_pRoot->createSceneManager(ST_GENERIC, "GameSceneMgr");
    m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f));

    m_pCamera = m_pSceneMgr->createCamera("GameCamera");
    m_pCamera->setPosition(Vector3(5, 60, 60));
    m_pCamera->lookAt(Vector3(5, 20, 0));
    m_pCamera->setNearClipDistance(5);

    m_pCamera->setAspectRatio(Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualWidth()) /
        Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualHeight()));
	OgreFramework::getSingletonPtr()->m_pTrayMgr->hideCursor();

    OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);

	// initialize position variables for the player
	playerFalling = false;
	playerSpeedX = 0;
	playerSpeedY = 0;
	playerSpeedZ = 0;

    buildGUI();

    createScene();
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool Game1State::pause()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Pausing GameState...");

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::resume()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Resuming GameState...");

    buildGUI();

    OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);
    m_bQuit = false;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::exit()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Leaving GameState...");

    m_pSceneMgr->destroyCamera(m_pCamera);
	m_pSceneMgr->clearScene();
	GameEntity::entitiesInitialized = false;
    if(m_pSceneMgr)
        OgreFramework::getSingletonPtr()->m_pRoot->destroySceneManager(m_pSceneMgr);

}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::createScene()
{
	if(!GameEntity::entitiesInitialized)
	{
		GameEntity::InitializeEntites(m_pSceneMgr);
	}
	loadLevel1();
	
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::loadLevel1() 
{
	// load the skybox
	m_pSceneMgr->setSkyBox(true, "SkyBoxes/SceneSkyBox1");

	// set the position of the player
	m_pCamera->setPosition(0, PLAYER_HEIGHT + 4.8, 0);

	Ogre::SceneNode* blocksNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("BlocksNode");


	// load the blocks
	Ogre::SceneNode* blockNode1 = blocksNode->createChildSceneNode("BlockNode1");
	blockNode1->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode2 = blocksNode->createChildSceneNode("BlockNode2");
	blockNode2->translate(0, 5, -110);
	blockNode2->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode3 = blocksNode->createChildSceneNode("BlockNode3");
	blockNode3->translate(30, 5, -220);
	blockNode3->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode4 = blocksNode->createChildSceneNode("BlockNode4");
	blockNode4->translate(-10, -10, -330);
	blockNode4->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode5 = blocksNode->createChildSceneNode("BlockNode5");
	blockNode5->translate(-100, 0, -430);
	blockNode5->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode6 = blocksNode->createChildSceneNode("BlockNode6");
	blockNode6->translate(-210, 15, -500);
	blockNode6->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode7 = blocksNode->createChildSceneNode("BlockNode7");
	blockNode7->translate(-330, 5, -550);
	blockNode7->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode8 = blocksNode->createChildSceneNode("BlockNode8");
	blockNode8->translate(-330, -15, -670);
	blockNode8->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode9 = blocksNode->createChildSceneNode("BlockNode9");
	blockNode9->translate(-330, 0, -780);
	blockNode9->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode10 = blocksNode->createChildSceneNode("BlockNode10");
	blockNode10->translate(-240, 0, -870);
	blockNode10->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode11 = blocksNode->createChildSceneNode("BlockNode11");
	blockNode11->translate(-140, -20, -970);
	blockNode11->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode12 = blocksNode->createChildSceneNode("BlockNode12");
	blockNode12->translate(-40, 0, -1080);
	blockNode12->attachObject(GameEntity::Block.getNewEntity());
	
	Ogre::SceneNode* blockNode13 = blocksNode->createChildSceneNode("BlockNode13");
	blockNode13->translate(70, 15, -1180);
	blockNode13->attachObject(GameEntity::Block.getNewEntity());
	
	Ogre::SceneNode* blockNode14 = blocksNode->createChildSceneNode("BlockNode14");
	blockNode14->translate(-10, 0, -1280);
	blockNode14->attachObject(GameEntity::Block.getNewEntity());
	
	Ogre::SceneNode* blockNode15 = blocksNode->createChildSceneNode("BlockNode15");
	blockNode15->translate(100, 15, -1380);
	blockNode15->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode16 = blocksNode->createChildSceneNode("BlockNode16");
	blockNode16->translate(210, 30, -1480);
	blockNode16->attachObject(GameEntity::Block.getNewEntity());
	
	Ogre::SceneNode* blockNode17 = blocksNode->createChildSceneNode("BlockNode17");
	blockNode17->translate(310, 40, -1590);
	blockNode17->attachObject(GameEntity::Block.getNewEntity());
	
	Ogre::SceneNode* blockNode18 = blocksNode->createChildSceneNode("BlockNode18");
	blockNode18->translate(420, 55, -1680);
	blockNode18->attachObject(GameEntity::Block.getNewEntity());
	
	Ogre::SceneNode* blockNode19 = blocksNode->createChildSceneNode("BlockNode19");
	blockNode19->translate(540, 65, -1780);
	blockNode19->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode20 = blocksNode->createChildSceneNode("BlockNode20");
	blockNode20->translate(650, 0, -1800);
	blockNode20->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode21 = blocksNode->createChildSceneNode("BlockNode21");
	blockNode21->translate(760, 10, -1800);
	blockNode21->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode22 = blocksNode->createChildSceneNode("BlockNode22");
	blockNode22->translate(860, 20, -1900);
	blockNode22->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode23 = blocksNode->createChildSceneNode("BlockNode23");
	blockNode23->translate(820, 30, -2020);
	blockNode23->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode24 = blocksNode->createChildSceneNode("BlockNode24");
	blockNode24->translate(720, 35, -2120);
	blockNode24->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode25 = blocksNode->createChildSceneNode("BlockNode25");
	blockNode25->translate(620, 0, -2220);
	blockNode25->attachObject(GameEntity::Block.getNewEntity());
	
	Ogre::SceneNode* blockNode26 = blocksNode->createChildSceneNode("BlockNode26");
	blockNode26->translate(580, 15, -2330);
	blockNode26->attachObject(GameEntity::Block.getNewEntity());
	
	Ogre::SceneNode* blockNode27 = blocksNode->createChildSceneNode("BlockNode27");
	blockNode27->translate(650, 30, -2440);
	blockNode27->attachObject(GameEntity::Block.getNewEntity());
	
	Ogre::SceneNode* blockNode28 = blocksNode->createChildSceneNode("BlockNode28");
	blockNode28->translate(760, 35, -2450);
	blockNode28->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode29 = blocksNode->createChildSceneNode("BlockNode29");
	blockNode29->translate(880, 20, -2430);
	blockNode29->attachObject(GameEntity::Block.getNewEntity());

	Ogre::SceneNode* blockNode30 = blocksNode->createChildSceneNode("BlockNodeVictory");
	blockNode30->translate(1000, 0, -2380);
	blockNode30->attachObject(GameEntity::Block.getNewEntity("blockVictory"));

	// loads the hazards
	Ogre::SceneNode* hazardsNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("HazardsNode");

	Ogre::SceneNode* hazardNode1 = hazardsNode->createChildSceneNode("HazardNode1");
	hazardNode1->translate(0, 20, -50);
	hazardNode1->yaw(Ogre::Degree(180));
	hazardNode1->attachObject(GameEntity::Bottle.getNewEntity());

	Ogre::SceneNode* hazardNode2 = hazardsNode->createChildSceneNode("HazardNode2");
	hazardNode2->translate(5, 20, -120);
	hazardNode2->yaw(Ogre::Degree(180));
	hazardNode2->attachObject(GameEntity::Pill.getNewEntity());

	Ogre::SceneNode* hazardNode3 = hazardsNode->createChildSceneNode("HazardNode3");
	hazardNode3->translate(20, 25, -220);
	hazardNode3->yaw(Ogre::Degree(180));
	hazardNode3->attachObject(GameEntity::Bottle.getNewEntity());

	Ogre::SceneNode* hazardNode4 = hazardsNode->createChildSceneNode("HazardNode4");
	hazardNode4->translate(-100, 25, -420);
	hazardNode4->yaw(Ogre::Degree(180));
	hazardNode4->attachObject(GameEntity::Bottle.getNewEntity());

	Ogre::SceneNode* hazardNode5 = hazardsNode->createChildSceneNode("HazardNode5");
	hazardNode5->translate(-310, 25, -620);
	hazardNode5->yaw(Ogre::Degree(180));
	hazardNode5->attachObject(GameEntity::Pill.getNewEntity());
	
	Ogre::SceneNode* hazardNode6 = hazardsNode->createChildSceneNode("HazardNode6");
	hazardNode6->translate(-300, 30, -820);
	hazardNode6->attachObject(GameEntity::Bottle.getNewEntity());

	Ogre::SceneNode* hazardNode7 = hazardsNode->createChildSceneNode("HazardNode7");
	hazardNode7->translate(-120, 30, -1020);
	hazardNode7->yaw(Ogre::Degree(180));
	hazardNode7->attachObject(GameEntity::Pill.getNewEntity());

	Ogre::SceneNode* hazardNode8 = hazardsNode->createChildSceneNode("HazardNode8");
	hazardNode8->translate(10, 35, -1220);
	hazardNode8->yaw(Ogre::Degree(180));
	hazardNode8->attachObject(GameEntity::Bottle.getNewEntity());

	Ogre::SceneNode* hazardNode9 = hazardsNode->createChildSceneNode("HazardNode9");
	hazardNode9->translate(110, 35, -1360);
	hazardNode9->yaw(Ogre::Degree(180));
	hazardNode9->attachObject(GameEntity::Bottle.getNewEntity());

	Ogre::SceneNode* hazardNode10 = hazardsNode->createChildSceneNode("HazardNode10");
	hazardNode10->translate(280, 65, -1600);
	hazardNode10->yaw(Ogre::Degree(180));
	hazardNode10->attachObject(GameEntity::Bottle.getNewEntity());

	Ogre::SceneNode* hazardNode11 = hazardsNode->createChildSceneNode("HazardNode11");
	hazardNode11->translate(520, 90, -1790);
	hazardNode11->yaw(Ogre::Degree(180));
	hazardNode11->attachObject(GameEntity::Pill.getNewEntity());

	Ogre::SceneNode* hazardNode12 = hazardsNode->createChildSceneNode("HazardNode12");
	hazardNode12->translate(720, 30, -1790);
	hazardNode12->yaw(Ogre::Degree(180));
	hazardNode12->attachObject(GameEntity::Bottle.getNewEntity());

	Ogre::SceneNode* hazardNode13 = hazardsNode->createChildSceneNode("HazardNode13");
	hazardNode13->translate(820, 55, -2000);
	hazardNode13->yaw(Ogre::Degree(180));
	hazardNode13->attachObject(GameEntity::Bottle.getNewEntity());

	Ogre::SceneNode* hazardNode14 = hazardsNode->createChildSceneNode("HazardNode14");
	hazardNode14->translate(620, 30, -2200);
	hazardNode14->yaw(Ogre::Degree(180));
	hazardNode14->attachObject(GameEntity::Pill.getNewEntity());

	Ogre::SceneNode* hazardNode15 = hazardsNode->createChildSceneNode("HazardNode15");
	hazardNode15->translate(620, 55, -2420);
	hazardNode15->yaw(Ogre::Degree(180));
	hazardNode15->attachObject(GameEntity::Pill.getNewEntity());

	Ogre::SceneNode* hazardNode16 = hazardsNode->createChildSceneNode("HazardNode16");
	hazardNode16->translate(890, 45, -2440);
	hazardNode16->yaw(Ogre::Degree(180));
	hazardNode16->attachObject(GameEntity::Bottle.getNewEntity());

	// loads the bonus
	Ogre::SceneNode* BonusesNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("BonusesNode");

	Ogre::SceneNode* BonusNode1 = BonusesNode->createChildSceneNode("BonusNode1");
	BonusNode1->translate(-20, 35, -120);
	BonusNode1->scale(4, 10, 10);
	BonusNode1->attachObject(GameEntity::Pillow.getNewEntity());

	Ogre::SceneNode* BonusNode2 = BonusesNode->createChildSceneNode("BonusNode2");
	BonusNode2->translate(50, 25, -280);
	BonusNode2->scale(0.2f, 0.2f, 0.2f);
	BonusNode2->attachObject(GameEntity::ChocBar.getNewEntity());

	Ogre::SceneNode* BonusNode3 = BonusesNode->createChildSceneNode("BonusNode3");
	BonusNode3->translate(-150, 35, -475);
	BonusNode3->scale(0.15f, 0.15f, 0.15f);
	BonusNode3->attachObject(GameEntity::Apple.getNewEntity());

	Ogre::SceneNode* BonusNode4 = BonusesNode->createChildSceneNode("BonusNode4");
	BonusNode4->translate(-190, 25, -900);
	BonusNode4->scale(0.15f, 0.15f, 0.15f);
	BonusNode4->attachObject(GameEntity::Apple.getNewEntity());

	Ogre::SceneNode* BonusNode5 = BonusesNode->createChildSceneNode("BonusNode5");
	BonusNode5->translate(20, 30, -1100);
	BonusNode5->scale(4.0f, 10.0f, 10.0f);
	BonusNode5->attachObject(GameEntity::Pillow.getNewEntity());

	Ogre::SceneNode* BonusNode6 = BonusesNode->createChildSceneNode("BonusNode6");
	BonusNode6->translate(200, 55, -1430);
	BonusNode6->scale(0.2f, 0.2f, 0.2f);
	BonusNode6->attachObject(GameEntity::ChocBar.getNewEntity());

	Ogre::SceneNode* BonusNode7 = BonusesNode->createChildSceneNode("BonusNode7");
	BonusNode7->translate(370, 65, -1620);
	BonusNode7->scale(0.15f, 0.15f, 0.15f);
	BonusNode7->attachObject(GameEntity::Apple.getNewEntity());

	Ogre::SceneNode* BonusNode8 = BonusesNode->createChildSceneNode("BonusNode8");
	BonusNode8->translate(600, 45, -1760);
	BonusNode8->scale(0.15f, 0.15f, 0.15f);
	BonusNode8->attachObject(GameEntity::Apple.getNewEntity());

	Ogre::SceneNode* BonusNode9 = BonusesNode->createChildSceneNode("BonusNode9");
	BonusNode9->translate(830, 45, -1840);
	BonusNode9->scale(0.15f, 0.15f, 0.15f);
	BonusNode9->attachObject(GameEntity::ChocBar.getNewEntity());

	Ogre::SceneNode* BonusNode10 = BonusesNode->createChildSceneNode("BonusNode10");
	BonusNode10->translate(680, 45, -2200);
	BonusNode10->scale(4.0f, 10.0f, 10.0f);
	BonusNode10->attachObject(GameEntity::Pillow.getNewEntity());

	Ogre::SceneNode* BonusNode11 = BonusesNode->createChildSceneNode("BonusNode11");
	BonusNode11->translate(700, 45, -2480);
	BonusNode11->scale(4.0f, 10.0f, 10.0f);
	BonusNode11->attachObject(GameEntity::Pillow.getNewEntity());
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool Game1State::keyPressed(const OIS::KeyEvent &keyEventRef)
{
	if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
    {
        m_bQuit = true;
        return true;
    }

	if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_SPACE) 
		&& !playerFalling)
    {
        playerFalling = true;
		playerSpeedY = JUMPING_SPEED;
        return true;
    }

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool Game1State::keyReleased(const OIS::KeyEvent &keyEventRef)
{
    if(OgreFramework::getSingletonPtr()->keyReleased(keyEventRef)) return true;

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool Game1State::mouseMoved(const OIS::MouseEvent &evt)
{
    if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseMove(evt)) return true;
	
	m_pCamera->yaw(Degree(evt.state.X.rel * -0.1f));
    m_pCamera->pitch(Degree(evt.state.Y.rel * -0.1f));

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool Game1State::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseDown(evt, id)) return true;

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool Game1State::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseUp(evt, id)) return true;


    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::onLeftPressed(const OIS::MouseEvent &evt)
{
	
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::movePlayerFromInput()
{
	playerSpeedX = 0.0f;
	playerSpeedY = 0.0f;
	playerSpeedZ = 0.0f;

	if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_Z)
		|| OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_W))
    {
		Ogre::Vector3 direction(m_pCamera->getRealDirection());

		direction.y = 0.0f;
		direction.normalise();
		direction.x *= PLAYER_SPEED;
		direction.z *= PLAYER_SPEED;

		playerSpeedX += direction.x;
		playerSpeedZ += direction.z;


		m_pCamera->move(direction);
	} 
	else if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_S)) 
	{
		Ogre::Vector3 direction(m_pCamera->getRealDirection());

		direction.y = 0.0f;
		direction.normalise();
		direction.x *= -PLAYER_SPEED;
		direction.z *= -PLAYER_SPEED;

		playerSpeedX += direction.x;
		playerSpeedZ += direction.z;

		m_pCamera->move(direction);
	}

	if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_A)
		|| OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_Q))
    {
		Ogre::Vector3 direction(m_pCamera->getRealRight());

		direction.y = 0.0f;
		direction.normalise();
		direction.x *= -PLAYER_SPEED;
		direction.z *= -PLAYER_SPEED;

		playerSpeedX += direction.x;
		playerSpeedZ += direction.z;

		m_pCamera->move(direction);
	} 
	else if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_D)) 
	{
		Ogre::Vector3 direction(m_pCamera->getRealRight());

		direction.y = 0;
		direction.normalise();
		direction.x *= PLAYER_SPEED;
		direction.z *= PLAYER_SPEED;

		playerSpeedX += direction.x;
		playerSpeedZ += direction.z;

		m_pCamera->move(direction);
	}


}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::getInput()
{
	
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::update(double timeSinceLastFrame)
{
    m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame;
    OgreFramework::getSingletonPtr()->m_pTrayMgr->frameRenderingQueued(m_FrameEvent);

    if(m_bQuit == true)
    {
        shutdown();
        return;
    }

	timeLeftBar->setProgress(timeLeftBar->getProgress() + PROGRESS1_PER_MILISECOND*timeSinceLastFrame);

	updatePlayerPosition(timeSinceLastFrame);
	updateMap(timeSinceLastFrame);
	updateHazardsAndBonusesCollisions();
    getInput();

	checkVictoryOrLose();
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::updateMap(double timeSinceLastFrame)
{
	// update the position of moving hazards
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::updateHazardsAndBonusesCollisions()
{
	// computes the player bounding box
	Ogre::AxisAlignedBox playerBoundingBox(
		m_pCamera->getRealPosition().x - PLAYER_OFFSET,
		m_pCamera->getRealPosition().y - PLAYER_HEIGHT,
		m_pCamera->getRealPosition().z - PLAYER_OFFSET,
		m_pCamera->getRealPosition().x + PLAYER_OFFSET,
		m_pCamera->getRealPosition().y + PLAYER_OFFSET,
		m_pCamera->getRealPosition().z + PLAYER_OFFSET);

	Ogre::SceneNode * collideNode = checkCollisionWithHazards(playerBoundingBox);

	if(collideNode)
	{
		// collision with an hazard
		collideNode->detachAllObjects();
		collideNode->getParent()->removeChild(collideNode->getName());
		timeLeftBar->setProgress(timeLeftBar->getProgress() + PROGRESS1_PER_HAZARD);
	}

	// check the collision with a bonus
	collideNode = checkCollisionWithBonuses(playerBoundingBox);

	if(collideNode)
	{
		// collision with a bonus
		collideNode->detachAllObjects();
		collideNode->getParent()->removeChild(collideNode->getName());
		timeLeftBar->setProgress(timeLeftBar->getProgress() + PROGRESS1_PER_BONUS);
		if(timeLeftBar->getProgress() > 1.0f)
		{
			timeLeftBar->setProgress(1.0f);
		}
	}
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::updatePlayerPosition(double timeSinceLastFrame)
{
	
	if(playerFalling)
	{
		// compute new position
		Ogre::Vector3 oldPosition(m_pCamera->getRealPosition());
		oldPosition.y -= PLAYER_HEIGHT;
		Ogre::Vector3 newPosition(oldPosition);

		newPosition.x += playerSpeedX;
		newPosition.z += playerSpeedZ;

		playerSpeedY += timeSinceLastFrame*GRAVITY;
		if(playerSpeedY < MAX_FALLING_SPEED)
		{
			playerSpeedY = MAX_FALLING_SPEED;
		}
		newPosition.y += playerSpeedY;

		// check collision
		if(checkCollisionWithBlocks(oldPosition, newPosition))
		{
			// get the axis and update the position
			if(newPosition.y - oldPosition.y < fabsf(playerSpeedY)
				&& oldPosition.y - newPosition.y < fabsf(playerSpeedY))
			{
				// vertical collision
				playerFalling = false;
				playerSpeedY = newPosition.y - oldPosition.y;
				m_pCamera->move(Ogre::Vector3(playerSpeedX, playerSpeedY, playerSpeedZ));
				playerSpeedY = 0;
			}
			else if(newPosition.z - oldPosition.z < fabsf(playerSpeedZ)
				&& oldPosition.z - newPosition.z < fabsf(playerSpeedZ))
			{
				playerSpeedZ = newPosition.z - oldPosition.z;
				m_pCamera->move(Ogre::Vector3(playerSpeedX, playerSpeedY, playerSpeedZ));
				playerSpeedZ = 0;
			}
			else
			{
				playerSpeedX = newPosition.x - oldPosition.x;
				m_pCamera->move(Ogre::Vector3(playerSpeedX, playerSpeedY, playerSpeedZ));
				playerSpeedX = 0;
			}
		}
		else 
		{
			m_pCamera->move(Ogre::Vector3(playerSpeedX, playerSpeedY, playerSpeedZ));
		}
	}
	else
	{
		// get input and move player
		// update position
		movePlayerFromInput();
		// check collision & update falling
		Ogre::Vector3 playerFeetPosition(m_pCamera->getRealPosition());
		playerFeetPosition.y -= PLAYER_HEIGHT + 0.1f;
		Ogre::Vector3 oldPlayerFeetPosition(playerFeetPosition);
		playerFeetPosition.y -= 0.1f;

		if(!checkCollisionWithBlocks(oldPlayerFeetPosition, playerFeetPosition))
		{
			playerFalling = true;
		}
	}
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool Game1State::checkCollisionWithBlocks(Ogre::Vector3 oldPoint, Ogre::Vector3 &newPoint)
{
	Ogre::Node::ChildNodeIterator it = 
		m_pSceneMgr->getRootSceneNode()->getChild("BlocksNode")->getChildIterator();

	Ogre::SceneNode* currentNode;

	while(it.hasMoreElements())
	{
		 currentNode = dynamic_cast<Ogre::SceneNode*>(it.getNext());

		 Ogre::SceneNode::ObjectIterator entityIt = currentNode->getAttachedObjectIterator();

		 Ogre::Entity* currentEntity;

		 while(entityIt.hasMoreElements())
		{
			currentEntity = dynamic_cast<Ogre::Entity*>(entityIt.getNext());

			// translate and scale points, to fit the transformations of the bounding box
			Vector3 realNewPoint(newPoint);
			realNewPoint.x -= currentNode->getPosition().x;
			realNewPoint.y -= currentNode->getPosition().y;
			realNewPoint.z -= currentNode->getPosition().z;
			realNewPoint.x = realNewPoint.x / currentNode->getScale().x;
			realNewPoint.y = realNewPoint.y / currentNode->getScale().y;
			realNewPoint.z = realNewPoint.z / currentNode->getScale().z;

			Vector3 realOldPoint(oldPoint);
			realOldPoint.x -= currentNode->getPosition().x;
			realOldPoint.y -= currentNode->getPosition().y;
			realOldPoint.z -= currentNode->getPosition().z;
			realOldPoint.x = realOldPoint.x / currentNode->getScale().x;
			realOldPoint.y = realOldPoint.y / currentNode->getScale().y;
			realOldPoint.z = realOldPoint.z / currentNode->getScale().z;

			// check collision
			if(currentEntity->getBoundingBox().intersects(realNewPoint))
			{
				if(newPoint.y < oldPoint.y
					&&currentEntity->getBoundingBox().getMaximum().y < realOldPoint.y) // y-collision
				{
					newPoint.y = currentEntity->getBoundingBox().getMaximum().y + 0.05
						+ currentNode->getPosition().y;
				}
				else if(newPoint.z > oldPoint.z 
					&& currentEntity->getBoundingBox().getMinimum().z > realOldPoint.z) // z-collision
				{
					newPoint.z = currentEntity->getBoundingBox().getMinimum().z - 0.05 
						+ currentNode->getPosition().z;
				}
				else if(newPoint.z < oldPoint.z 
					&& currentEntity->getBoundingBox().getMaximum().z < realOldPoint.z)
				{
					newPoint.z = currentEntity->getBoundingBox().getMaximum().z + 0.05
						+ currentNode->getPosition().z;
				}
				else if(newPoint.x < oldPoint.x)// x collision
				{
					newPoint.x = currentEntity->getBoundingBox().getMaximum().x + 0.05
						+ currentNode->getPosition().x;
				}
				else
				{
					newPoint.x = currentEntity->getBoundingBox().getMinimum().x - 0.05
						+ currentNode->getPosition().x;
				}

				return true;
			}
		}
	}

	return false;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

Ogre::SceneNode* Game1State::checkCollisionWithHazards(Ogre::AxisAlignedBox &box)
{
	Ogre::Node::ChildNodeIterator it = 
		m_pSceneMgr->getRootSceneNode()->getChild("HazardsNode")->getChildIterator();

	Ogre::SceneNode* currentNode;

	while(it.hasMoreElements())
	{
		 currentNode = dynamic_cast<Ogre::SceneNode*>(it.getNext());

		 Ogre::SceneNode::ObjectIterator entityIt = currentNode->getAttachedObjectIterator();

		 Ogre::Entity* currentEntity;

		 while(entityIt.hasMoreElements())
		{
			currentEntity = dynamic_cast<Ogre::Entity*>(entityIt.getNext());

			Ogre::AxisAlignedBox playerBox(box);

			playerBox.getMinimum().x -= currentNode->getPosition().x;
			playerBox.getMinimum().y -= currentNode->getPosition().y;
			playerBox.getMinimum().z -= currentNode->getPosition().z;
			playerBox.getMinimum().x = playerBox.getMinimum().x / currentNode->getScale().x;
			playerBox.getMinimum().y = playerBox.getMinimum().y / currentNode->getScale().y;
			playerBox.getMinimum().z = playerBox.getMinimum().z / currentNode->getScale().z;

			playerBox.getMaximum().x -= currentNode->getPosition().x;
			playerBox.getMaximum().y -= currentNode->getPosition().y;
			playerBox.getMaximum().z -= currentNode->getPosition().z;
			playerBox.getMaximum().x = playerBox.getMaximum().x / currentNode->getScale().x;
			playerBox.getMaximum().y = playerBox.getMaximum().y / currentNode->getScale().y;
			playerBox.getMaximum().z = playerBox.getMaximum().z / currentNode->getScale().z;

			// check collision
			if(currentEntity->getBoundingBox().intersects(playerBox))
			{
				return currentNode;
			}
		}
	}

	return NULL;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

Ogre::SceneNode* Game1State::checkCollisionWithBonuses(Ogre::AxisAlignedBox &box)
{
	Ogre::Node::ChildNodeIterator it = 
		m_pSceneMgr->getRootSceneNode()->getChild("BonusesNode")->getChildIterator();

	Ogre::SceneNode* currentNode;

	while(it.hasMoreElements())
	{
		 currentNode = dynamic_cast<Ogre::SceneNode*>(it.getNext());

		 Ogre::SceneNode::ObjectIterator entityIt = currentNode->getAttachedObjectIterator();

		 Ogre::Entity* currentEntity;

		 while(entityIt.hasMoreElements())
		{
			currentEntity = dynamic_cast<Ogre::Entity*>(entityIt.getNext());

			Ogre::AxisAlignedBox playerBox(box);

			playerBox.getMinimum().x -= currentNode->getPosition().x;
			playerBox.getMinimum().y -= currentNode->getPosition().y;
			playerBox.getMinimum().z -= currentNode->getPosition().z;
			playerBox.getMinimum().x = playerBox.getMinimum().x / currentNode->getScale().x;
			playerBox.getMinimum().y = playerBox.getMinimum().y / currentNode->getScale().y;
			playerBox.getMinimum().z = playerBox.getMinimum().z / currentNode->getScale().z;

			playerBox.getMaximum().x -= currentNode->getPosition().x;
			playerBox.getMaximum().y -= currentNode->getPosition().y;
			playerBox.getMaximum().z -= currentNode->getPosition().z;
			playerBox.getMaximum().x = playerBox.getMaximum().x / currentNode->getScale().x;
			playerBox.getMaximum().y = playerBox.getMaximum().y / currentNode->getScale().y;
			playerBox.getMaximum().z = playerBox.getMaximum().z / currentNode->getScale().z;

			// check collision
			if(currentEntity->getBoundingBox().intersects(playerBox))
			{
				return currentNode;
			}
		}
	}

	return NULL;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::buildGUI()
{
    OgreFramework::getSingletonPtr()->m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);

	timeLeftBar = OgreFramework::getSingletonPtr()->m_pTrayMgr->createProgressBar(OgreBites::TL_TOP, "Timer", "Time Remaining:", 500, 0);
	timeLeftBar->setProgress(1.0f);
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::loseGame()
{
	Game1FinishedState* state = (Game1FinishedState*) findByName("Game1FinishedState");

	state->setGameWon(false);
	changeAppState(state);
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::winGame()
{
	Game1FinishedState* state = (Game1FinishedState*) findByName("Game1FinishedState");

	state->setGameWon(true);
	changeAppState(state);
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void Game1State::checkVictoryOrLose()
{
	// check lose
	if(m_pCamera->getPosition().y < -100.0f) // the player fell off
	{
		loseGame();
		return;
	}

	if(timeLeftBar->getProgress() <= 0.0f) // no time left
	{
		loseGame();
		return;
	}

	// check win
	// get the node of the victory...
	Ogre::SceneNode* nodeVictory = 
		dynamic_cast<Ogre::SceneNode*>(
		dynamic_cast<Ogre::SceneNode*>(m_pSceneMgr->getRootSceneNode()
		->getChild("BlocksNode"))->getChild("BlockNodeVictory"));

	// get the block of the victory
	Ogre::Entity* blockVictory = dynamic_cast<Ogre::Entity*>(nodeVictory->getAttachedObject("blockVictory"));

	// check the collision
	Vector3 playerFeetPosition(m_pCamera->getPosition());
	playerFeetPosition.x -= nodeVictory->getPosition().x;
	playerFeetPosition.y -= nodeVictory->getPosition().y + PLAYER_HEIGHT + 0.1f;
	playerFeetPosition.z -= nodeVictory->getPosition().z;
	playerFeetPosition.x = playerFeetPosition.x / nodeVictory->getScale().x;
	playerFeetPosition.y = playerFeetPosition.y / nodeVictory->getScale().y;
	playerFeetPosition.z = playerFeetPosition.z / nodeVictory->getScale().z;

	if(blockVictory->getBoundingBox().intersects(playerFeetPosition))
	{
		// the player won!!
		winGame();
	}
}

//|||||||||||||||||||||||||||||||||||||||||||||||
